package parser

import (
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var (
	// 匹配文本插入表达式: #{expression}
	textExprRegex = regexp.MustCompile(`#\{((?:[^{}]|\{[^}]*\})*)\}`)
	// 匹配参数化表达式: {expression} （支持嵌套大括号）
	paramExprRegex = regexp.MustCompile(`\{((?:[^{}]|\{[^}]*\})*)\}`)
)

// Parser GoX 解析器
type Parser struct {
	fset *token.FileSet
}

// NewParser 创建新的解析器
func NewParser() *Parser {
	return &Parser{
		fset: token.NewFileSet(),
	}
}

// ParseFile 解析 .gox 文件
func (p *Parser) ParseFile(filename string, src []byte) (*GoxFile, error) {
	// 先预处理文件，替换 SQL 块为合法的 Go 代码
	processed, sqlBlocks, err := p.preprocessFile(src)
	if err != nil {
		return nil, fmt.Errorf("预处理失败: %w", err)
	}

	// 解析处理后的 Go 代码
	file, err := parser.ParseFile(p.fset, filename, processed, parser.ParseComments)
	if err != nil {
		return nil, fmt.Errorf("解析 Go 代码失败: %w", err)
	}

	return &GoxFile{
		File:          file,
		SQLBlocks:     sqlBlocks,
		GeneratedCode: string(processed),
	}, nil
}

// preprocessFile 预处理文件，提取 SQL 块并替换为 Go 代码
func (p *Parser) preprocessFile(src []byte) ([]byte, []*SQLBlock, error) {
	content := string(src)
	var sqlBlocks []*SQLBlock
	sqlCounter := 0

	// 使用智能方法查找所有 SQL 块（支持嵌套）
	sqlBlockInfo := p.findSQLBlocks(content)

	// 从后往前替换，避免位置偏移问题
	for i := len(sqlBlockInfo) - 1; i >= 0; i-- {
		info := sqlBlockInfo[i]

		sqlContent := info.Content
		varName := fmt.Sprintf("__gox_sql_%d", sqlCounter)
		sqlCounter++

		// 解析 SQL 块内容
		sqlBlock, err := p.parseSQLBlock(sqlContent, varName)
		if err != nil {
			fmt.Printf("调试: 解析SQL块失败，内容: %q, 错误: %v\n", sqlContent, err)
			return nil, nil, fmt.Errorf("解析 SQL 块失败: %w", err)
		}

		// 添加到块列表的开头（因为我们是倒序处理的）
		sqlBlocks = append([]*SQLBlock{sqlBlock}, sqlBlocks...)

		// 替换为 Go 代码
		replacement := p.generateGoCodeForSQL(sqlBlock)
		content = content[:info.Start] + replacement + content[info.End:]
	}

	return []byte(content), sqlBlocks, nil
}

// ExpressionMatch 表示找到的表达式匹配
type ExpressionMatch struct {
	Start   int
	End     int
	Content string
	Type    SQLExpressionType
}

// parseSQLBlock 解析 SQL 块内容
func (p *Parser) parseSQLBlock(sqlContent, varName string) (*SQLBlock, error) {
	var nodes []SQLNode

	// 查找所有表达式
	expressions := p.findAllExpressions(sqlContent)

	if len(expressions) == 0 {
		// 没有表达式，整个内容都是文本
		if len(sqlContent) > 0 {
			nodes = append(nodes, &SQLText{
				Text: sqlContent,
			})
		}
	} else {
		// 按顺序处理表达式和文本
		lastEnd := 0
		for _, expr := range expressions {
			// 添加表达式之前的文本
			if expr.Start > lastEnd {
				text := sqlContent[lastEnd:expr.Start]
				if len(text) > 0 {
					nodes = append(nodes, &SQLText{
						Text: text,
					})
				}
			}

			// 解析表达式
			sqlExpr, err := p.parseExpression(expr.Content, expr.Type)
			if err != nil {
				return nil, fmt.Errorf("解析表达式 '%s' 失败: %w", expr.Content, err)
			}

			nodes = append(nodes, sqlExpr)
			lastEnd = expr.End
		}

		// 添加最后剩余的文本
		if lastEnd < len(sqlContent) {
			text := sqlContent[lastEnd:]
			if len(text) > 0 {
				nodes = append(nodes, &SQLText{
					Text: text,
				})
			}
		}
	}

	return &SQLBlock{
		Content: nodes,
		VarName: varName,
	}, nil
}

// findAllExpressions 查找所有表达式
func (p *Parser) findAllExpressions(content string) []ExpressionMatch {
	var matches []ExpressionMatch
	i := 0

	for i < len(content) {
		// 查找 #{...} 表达式
		if i < len(content)-1 && content[i] == '#' && content[i+1] == '{' {
			start := i
			exprContent, end := p.findMatchingBrace(content, i+2) // 跳过 #{
			if end != -1 {
				matches = append(matches, ExpressionMatch{
					Start:   start,
					End:     end + 1, // 包含结束的 }
					Content: exprContent,
					Type:    SQLExprParam,
				})
				i = end + 1
				continue
			}
		}

		// 查找 {...} 表达式 (但不是前面已经匹配的 #{...})
		if content[i] == '{' {
			// 确保这不是 #{...} 的一部分
			if i == 0 || content[i-1] != '#' {
				start := i
				exprContent, end := p.findMatchingBrace(content, i+1) // 跳过 {
				if end != -1 {
					matches = append(matches, ExpressionMatch{
						Start:   start,
						End:     end + 1, // 包含结束的 }
						Content: exprContent,
						Type:    SQLExprText,
					})
					i = end + 1
					continue
				}
			}
		}

		i++
	}

	// 按起始位置排序
	sort.Slice(matches, func(i, j int) bool {
		return matches[i].Start < matches[j].Start
	})

	return matches
}

// findMatchingBrace 找到匹配的右大括号，并返回内容和结束位置
func (p *Parser) findMatchingBrace(content string, start int) (string, int) {
	braceCount := 1
	i := start

	for i < len(content) && braceCount > 0 {
		switch content[i] {
		case '{':
			braceCount++
		case '}':
			braceCount--
		case '"':
			// 跳过字符串字面量
			i++
			for i < len(content) && content[i] != '"' {
				if content[i] == '\\' && i+1 < len(content) {
					i++ // 跳过转义字符
				}
				i++
			}
		case '\'':
			// 跳过字符字面量
			i++
			for i < len(content) && content[i] != '\'' {
				if content[i] == '\\' && i+1 < len(content) {
					i++ // 跳过转义字符
				}
				i++
			}
		case '`':
			// 跳过原始字符串字面量
			i++
			for i < len(content) && content[i] != '`' {
				i++
			}
		case '<':
			// 检查是否是 <sql> 标签，如果是则跳过整个 <sql>...</sql> 块
			if i+4 < len(content) && content[i:i+5] == "<sql>" {
				// 跳过到 </sql> 结束
				for i < len(content) {
					if i+5 < len(content) && content[i:i+6] == "</sql>" {
						i += 5 // 跳过 </sql>
						break
					}
					i++
				}
			}
		}
		i++
	}

	if braceCount == 0 {
		return content[start : i-1], i - 1 // 返回内容和结束位置（不包含}）
	}

	return "", -1 // 没有找到匹配的大括号
}

// parseExpression 解析表达式内容
func (p *Parser) parseExpression(content string, exprType SQLExpressionType) (*SQLExpression, error) {
	content = strings.TrimSpace(content)

	// 检查是否包含嵌套的gox.Sql调用
	if strings.Contains(content, "gox.Sql(") {
		// 预处理嵌套的gox.Sql调用
		processedContent, err := p.preprocessNestedSQL(content)
		if err != nil {
			// 如果嵌套Query处理失败，使用原始内容
			// 这样可以避免因嵌套问题导致整个编译失败
		} else {
			content = processedContent
		}
	}

	// 智能处理简单的gox.Sql调用，自动添加return
	content = p.autoAddReturn(content)

	// 处理 ${} 嵌套语法
	content = p.processDollarBlocks(content)

	// 尝试解析为简单表达式
	expr, err := parser.ParseExpr(content)
	if err == nil {
		// 成功解析为表达式
		return &SQLExpression{
			Type:    exprType,
			Content: content,
			Expr:    expr,
		}, nil
	}

	// 如果解析表达式失败，尝试解析为代码块（当作匿名函数）
	// 将内容包装成完整的包和函数来验证语法，包含必要的import
	wrappedContent := fmt.Sprintf(`package main

import (
	"database/sql"
	"fmt"
	"github.com/yourusername/gox/pkg/runtime"
)

func testFunc() interface{} {
%s
}`, content)

	// 尝试解析为完整文件来验证语法
	_, err = parser.ParseFile(p.fset, "", wrappedContent, 0)
	if err != nil {
		// 如果验证失败，我们仍然将其视为有效的代码块
		// 因为运行时可能有更多的上下文信息
		fmt.Printf("警告: 代码块语法验证失败，但将继续处理: %v\n", err)
	}

	return &SQLExpression{
		Type:    exprType,
		Content: content,
		Expr:    nil, // 复杂代码块没有简单表达式
	}, nil
}

// generateGoCodeForSQL 为 SQL 块生成对应的 Go 代码
func (p *Parser) generateGoCodeForSQL(block *SQLBlock) string {
	var parts []string

	parts = append(parts, fmt.Sprintf("%s := gox.NewSqlBuilder()", block.VarName+"_builder"))

	for _, node := range block.Content {
		switch n := node.(type) {
		case *SQLText:
			text := n.Text
			if strings.TrimSpace(text) != "" {
				// 将多行SQL压缩为单行，但保持可读性，同时保留前后的空格
				text = regexp.MustCompile(`\s+`).ReplaceAllString(text, " ")
				parts = append(parts, fmt.Sprintf("%s.AddText(%s)",
					block.VarName+"_builder", strconv.Quote(text)))
			}
		case *SQLExpression:
			switch n.Type {
			case SQLExprText:
				// 文本插入表达式 {expr} - 直接拼接到SQL中
				if n.Expr != nil {
					// 简单表达式
					parts = append(parts, fmt.Sprintf("%s.AddText(fmt.Sprintf(\"%%v\", %s))",
						block.VarName+"_builder", p.exprToString(n.Expr)))
				} else {
					// 复杂代码块 - 使用具名返回值包装
					codeContent := strings.ReplaceAll(n.Content, "\n", "\n\t\t\t")
					// 统一使用具名返回值，总是补充return __result确保语法正确
					parts = append(parts, fmt.Sprintf("if __result := func() (__result interface{}) {\n\t\t\t%s\n\t\t\treturn __result\n\t\t}(); __result != nil {\n\t\t\t%s.AddText(fmt.Sprintf(\"%%v\", __result))\n\t\t}",
						codeContent, block.VarName+"_builder"))
				}
			case SQLExprParam:
				// 参数化表达式 #{expr} - 使用参数占位符
				if n.Expr != nil {
					// 简单表达式
					parts = append(parts, fmt.Sprintf("%s.AddParam(%s)",
						block.VarName+"_builder", p.exprToString(n.Expr)))
				} else {
					// 复杂代码块 - 使用具名返回值包装
					codeContent := strings.ReplaceAll(n.Content, "\n", "\n\t\t\t")
					// 统一使用具名返回值，总是补充return __result确保语法正确
					parts = append(parts, fmt.Sprintf("if __result := func() (__result interface{}) {\n\t\t\t%s\n\t\t\treturn __result\n\t\t}(); __result != nil {\n\t\t\t%s.AddParam(__result)\n\t\t}",
						codeContent, block.VarName+"_builder"))
				}
			}
		}
	}

	parts = append(parts, fmt.Sprintf("%s := %s.Build()",
		block.VarName, block.VarName+"_builder"))

	return "func() *gox.Sql {\n\t\t" + strings.Join(parts, "\n\t\t") + "\n\t\treturn " + block.VarName + "\n\t}()"
}

// exprToString 将表达式转换为字符串
func (p *Parser) exprToString(expr ast.Expr) string {
	switch e := expr.(type) {
	case *ast.Ident:
		return e.Name
	case *ast.BasicLit:
		return e.Value
	case *ast.SelectorExpr:
		return p.exprToString(e.X) + "." + e.Sel.Name
	case *ast.CallExpr:
		// 处理函数调用
		fun := p.exprToString(e.Fun)
		var args []string
		for _, arg := range e.Args {
			args = append(args, p.exprToString(arg))
		}
		return fun + "(" + strings.Join(args, ", ") + ")"
	case *ast.UnaryExpr:
		return e.Op.String() + p.exprToString(e.X)
	case *ast.BinaryExpr:
		return p.exprToString(e.X) + " " + e.Op.String() + " " + p.exprToString(e.Y)
	case *ast.ParenExpr:
		return "(" + p.exprToString(e.X) + ")"
	default:
		// 对于其他复杂表达式，使用 go/format 包
		var buf strings.Builder
		err := format.Node(&buf, p.fset, expr)
		if err != nil {
			return "/* parse_error */"
		}
		return buf.String()
	}
}

// GetFileSet 返回文件集
func (p *Parser) GetFileSet() *token.FileSet {
	return p.fset
}

// preprocessNestedSQL 预处理代码块中嵌套的SQL块
func (p *Parser) preprocessNestedSQL(content string) (string, error) {
	result := content
	sqlCount := 0

	// 使用智能方法查找所有嵌套的 Query() 调用
	nestedBlocks := p.findSQLBlocks(result)

	// 从后往前替换，避免位置偏移问题
	for i := len(nestedBlocks) - 1; i >= 0; i-- {
		block := nestedBlocks[i]

		sqlContent := block.Content
		sqlBlock, err := p.parseSQLBlock(sqlContent, fmt.Sprintf("__nested_sql_%d", sqlCount))
		if err != nil {
			return "", fmt.Errorf("解析嵌套SQL块失败: %v", err)
		}

		// 生成嵌套SQL块的代码
		nestedCode := p.generateGoCodeForSQL(sqlBlock)

		// 替换原始的Query()调用
		result = result[:block.Start] + nestedCode + result[block.End:]

		sqlCount++
	}

	return result, nil
}

// SQLBlockInfo 表示找到的SQL块信息
type SQLBlockInfo struct {
	Start   int    // 块的开始位置（包含Query函数调用）
	End     int    // 块的结束位置（包含右括号）
	Content string // SQL内容（不包含Query函数调用和引号）
}

// findSQLBlocks 智能查找所有SQL块，支持嵌套 - 新语法 Query(`...`) 和 Query('...')
func (p *Parser) findSQLBlocks(content string) []SQLBlockInfo {
	var blocks []SQLBlockInfo
	i := 0

	for i < len(content) {
		// 跳过普通字符串字面量（双引号）
		if content[i] == '"' {
			i++
			for i < len(content) && content[i] != '"' {
				if content[i] == '\\' && i+1 < len(content) {
					i++ // 跳过转义字符
				}
				i++
			}
			if i < len(content) {
				i++ // 跳过结束引号
			}
			continue
		}

		// 查找 "gox.Sql(" 函数调用
		var queryPos, funcLen int
		var isQueryCall bool

		if i+8 <= len(content) && content[i:i+8] == "gox.Sql(" {
			queryPos = i
			funcLen = 8
			isQueryCall = true
		}

		if isQueryCall {
			j := i + funcLen // 跳过 "Query(" 或 "Q("

			// 跳过空格
			for j < len(content) && (content[j] == ' ' || content[j] == '\t' || content[j] == '\n') {
				j++
			}

			// 检查字符串类型：反引号或单引号
			var quoteChar byte
			var isRawString bool

			if j < len(content) && content[j] == '`' {
				quoteChar = '`'
				isRawString = true
			} else if j < len(content) && content[j] == '\'' {
				quoteChar = '\''
				isRawString = false
			} else {
				// 不是我们要的Query调用
				i = queryPos + 5
				continue
			}

			// 查找匹配的结束引号
			contentStart := j + 1 // 跳过开始引号
			sqlEnd := p.findMatchingQuote(content, contentStart, quoteChar, isRawString)

			if sqlEnd == -1 {
				// 没有找到匹配的结束引号
				i = j + 1
				continue
			}

			// 查找函数调用的结束括号
			closeParenPos := sqlEnd + 1 // 跳过结束引号
			for closeParenPos < len(content) && (content[closeParenPos] == ' ' || content[closeParenPos] == '\t' || content[closeParenPos] == '\n') {
				closeParenPos++
			}

			if closeParenPos >= len(content) || content[closeParenPos] != ')' {
				// 没有找到结束括号
				i = j + 1
				continue
			}

			// 提取SQL内容
			sqlContent := content[contentStart:sqlEnd]

			blocks = append(blocks, SQLBlockInfo{
				Start:   queryPos,
				End:     closeParenPos + 1, // 包含结束括号
				Content: sqlContent,
			})

			i = closeParenPos + 1
		} else {
			i++
		}
	}

	return blocks
}

// autoAddReturn 智能添加return语句
func (p *Parser) autoAddReturn(content string) string {
	lines := strings.Split(content, "\n")

	// 移除空行和注释，只保留实际代码行
	var codeLines []string
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed != "" && !strings.HasPrefix(trimmed, "//") {
			codeLines = append(codeLines, trimmed)
		}
	}

	// 如果只有一行代码，且是gox.Sql()调用，自动添加return
	if len(codeLines) == 1 {
		line := codeLines[0]
		if strings.HasPrefix(line, "gox.Sql(") &&
			!strings.HasPrefix(line, "return ") {
			return "return " + content
		}
	}

	return content
}

// processDollarBlocks 处理 ${} 嵌套语法，支持递归嵌套
func (p *Parser) processDollarBlocks(content string) string {
	return p.processDollarBlocksRecursive(content)
}

// processDollarBlocksRecursive 递归处理 ${} 块，支持复杂嵌套
func (p *Parser) processDollarBlocksRecursive(content string) string {
	result := content

	// 从后往前处理，避免位置偏移问题
	for {
		lastStart := strings.LastIndex(result, "${")
		if lastStart == -1 {
			break
		}

		// 查找匹配的右大括号
		dollarContent, end := p.findMatchingBrace(result, lastStart+2)
		if end == -1 {
			break
		}

		// 递归处理内部的 ${} 块
		processedContent := p.processDollarBlocksRecursive(dollarContent)

		// 解析处理后的内容
		sqlParts, codeParts := p.parseDollarBlockContent(processedContent)

		// 生成替换代码
		var replacement string
		if len(codeParts) == 0 {
			// 纯SQL内容
			replacement = fmt.Sprintf(`return "%s"`, strings.TrimSpace(strings.Join(sqlParts, " ")))
		} else {
			// 包含代码块的复杂内容
			replacement = p.generateDollarBlockCode(sqlParts, codeParts)
		}

		result = result[:lastStart] + replacement + result[end+1:]
	}

	return result
}

// parseDollarBlockContent 解析 ${} 块内容，分离SQL文本和代码块
func (p *Parser) parseDollarBlockContent(content string) ([]string, []string) {
	var sqlParts []string
	var codeParts []string

	i := 0
	currentSQL := ""

	for i < len(content) {
		// 检查是否是 #{ 开头（参数化查询）
		if i < len(content)-1 && content[i] == '#' && content[i+1] == '{' {
			// 这是参数化查询，跳过处理，直接作为SQL文本
			currentSQL += string(content[i])
			i++
			continue
		}

		if content[i] == '{' {
			// 找到普通代码块
			if currentSQL != "" {
				sqlParts = append(sqlParts, strings.TrimSpace(currentSQL))
				currentSQL = ""
			}

			// 查找匹配的右大括号
			codeContent, end := p.findMatchingBrace(content, i+1)
			if end != -1 {
				codeParts = append(codeParts, codeContent)
				i = end + 1
			} else {
				i++
			}
		} else {
			currentSQL += string(content[i])
			i++
		}
	}

	if currentSQL != "" {
		sqlParts = append(sqlParts, strings.TrimSpace(currentSQL))
	}

	return sqlParts, codeParts
}

// generateDollarBlockCode 为复杂的 ${} 块生成代码
func (p *Parser) generateDollarBlockCode(sqlParts []string, codeParts []string) string {
	var parts []string

	// 构建复合返回语句
	parts = append(parts, "var __parts []string")

	// 添加初始SQL部分
	if len(sqlParts) > 0 && sqlParts[0] != "" {
		parts = append(parts, fmt.Sprintf(`__parts = append(__parts, "%s")`, sqlParts[0]))
	}

	// 添加代码块和后续SQL
	for i, code := range codeParts {
		// 添加代码块的结果
		parts = append(parts, fmt.Sprintf(`if __codeResult := func() string {
			%s
			return ""
		}(); __codeResult != "" {
			__parts = append(__parts, __codeResult)
		}`, code))

		// 添加后续的SQL部分
		if i+1 < len(sqlParts) && sqlParts[i+1] != "" {
			parts = append(parts, fmt.Sprintf(`__parts = append(__parts, "%s")`, sqlParts[i+1]))
		}
	}

	parts = append(parts, "return strings.Join(__parts, \" \")")

	return fmt.Sprintf("func() string {\n\t\t\t%s\n\t\t}()", strings.Join(parts, "\n\t\t\t"))
}

// findMatchingQuote 查找匹配的引号，支持转义
func (p *Parser) findMatchingQuote(content string, start int, quoteChar byte, isRawString bool) int {
	i := start

	for i < len(content) {
		if content[i] == quoteChar {
			// 找到匹配的结束引号
			return i
		}

		// 如果不是原始字符串，处理转义字符
		if !isRawString && content[i] == '\\' && i+1 < len(content) {
			i++ // 跳过转义字符
		}
		i++
	}

	return -1 // 没有找到匹配的引号
}

// findMatchingSQLBrace 查找匹配的右大括号，支持嵌套
func (p *Parser) findMatchingSQLBrace(content string, start int) int {
	i := start
	braceCount := 0

	for i < len(content) {
		switch content[i] {
		case '{':
			braceCount++
		case '}':
			if braceCount == 0 {
				// 找到匹配的右大括号
				return i
			}
			braceCount--
		case '"':
			// 跳过字符串字面量
			i++
			for i < len(content) && content[i] != '"' {
				if content[i] == '\\' && i+1 < len(content) {
					i++ // 跳过转义字符
				}
				i++
			}
		case '\'':
			// 跳过字符字面量
			i++
			for i < len(content) && content[i] != '\'' {
				if content[i] == '\\' && i+1 < len(content) {
					i++ // 跳过转义字符
				}
				i++
			}
		case '`':
			// 跳过原始字符串字面量
			i++
			for i < len(content) && content[i] != '`' {
				i++
			}
		}
		i++
	}

	return -1 // 没有找到匹配的右大括号
}
